package com.xuyuan.json.jackson.study;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;

import java.io.IOException;
import java.util.*;

public class WrapperArraysSerializer extends JsonSerializer implements ContextualSerializer {

    Class<?> clazz;
    Class<?> binding;

    Boolean hasArray;

    public WrapperArraysSerializer() {
    }

    public WrapperArraysSerializer(Class<?> clazz, Class<?> binding, Boolean hasArray) {
        this.clazz = clazz;
        this.binding = binding;
        this.hasArray = hasArray;
    }

    @Override
    public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (value == null) {
            return;
        }
        if (hasArray) {
            jsonGenerator.writeStartArray();
            jsonGenerator.writeObject(value);
            jsonGenerator.writeEndArray();
        } else {
            if (value instanceof List) {
                Iterator<?> iterator = ((List<?>) value).iterator();
                List<Object> list = new ArrayList<>();
                handleCollection(jsonGenerator, iterator, list);
            } else if (value instanceof Set) {
                Iterator<?> iterator = ((Set<?>) value).iterator();
                Set<Object> set = new HashSet<>();
                handleCollection(jsonGenerator, iterator, set);
            } else {
                jsonGenerator.writeObject(value);
            }
        }
    }

    private void handleCollection(JsonGenerator jsonGenerator, Iterator<?> iterator, Collection<Object> collection) throws IOException {
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            if (obj instanceof Map) {
                collection.add(BeanUtil.mapToBean((Map<?, ?>) obj, binding, false, CopyOptions.create()));
            } else {
                collection.add(obj);
            }
        }
        jsonGenerator.writeObject(collection);
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        WrapArray ann = beanProperty.getAnnotation(WrapArray.class);
        Class<?> clazz = ann.value();
        Class<?> bindings = ann.bindings();
        return new WrapperArraysSerializer(clazz, bindings, ann.hasArray());
    }
}
